package cate.game.role.trace;

import cate.common.game.GameCollection;
import cate.common.game.trace.entity.RoleTraceCareerLog;
import cate.common.game.trace.entity.RoleTraceDailyLog;
import cate.common.table.d.GDFunc;
import cate.common.table.pay.PayItemRow;
import cate.common.util.TimeTool;
import cate.game.role.Role;
import cate.game.role.RolePart;
import cate.game.role.trace.core.TracePayType;
import com.fasterxml.jackson.annotation.JsonIgnore;
import easy.java.dev.note.NoteField;
import org.springframework.data.mongodb.core.mapping.Document;

import java.util.Calendar;
import java.util.Date;

@Document(collection = GameCollection.NAME_ROLE_TRACE)
public class RoleTrace extends RolePart {
    @NoteField("每日打点数据")
    public RoleTraceDailyLog dailyLog;
    @NoteField("生涯打点数据")
    public RoleTraceCareerLog careerLog;
    @NoteField("当前完成的引导ID")
    public int guideId;
    @NoteField("设备ID")
    public String deviceId;
    @NoteField("客户端版本")
    public String clientVersion;
    @NoteField("平台")
    public String platform;
    @JsonIgnore
    @NoteField("在线时长开始统计时间")
    public long onlineStartTime;
    @JsonIgnore
    @NoteField("公会时长开始统计时间")
    public long inClubStartTime;

    public RoleTrace(){}

    public RoleTrace(Role role){
        super(role);
    }

    @Override
    public void initialize(Role role) {
        super.initialize(role);
    }

    @Override
    public void onEnter() {
        super.onEnter();
        if (dailyLog == null) {
            dailyLog = new RoleTraceDailyLog();
            initDaily();
        }
        if (careerLog == null) {
            careerLog = new RoleTraceCareerLog();
            initCareer();
        }
        onlineStartTime = System.currentTimeMillis();
        if (role.getRes().guild.getGuild() != null) {
            inClubStartTime = System.currentTimeMillis();
        } else {
            inClubStartTime = 0;
        }
        if (dailyLog.login_time == null) {
            dailyLog.login_time = new Date(role.getStatus().loginTime);
        }
        recordOnlineTraceDaily();
        dailyLog.login_count++;
        careerLog.login_count++;
    }

    @Override
    protected void offline() {
        super.offline();
        recordOnlineTime();
        recordInClubTime();
        saveLog();
    }

    @Override
    public void onDaySpan(boolean silence) {
        if (dailyLog == null || careerLog == null) {
            return;
        }
        super.onDaySpan(silence);
        if (!silence) {
            recordOnlineTime();
            recordInClubTime();
            saveLog();
        }
        long nowTime = System.currentTimeMillis();
        long oldTime = dailyLog.log_date.getTime();
        // 计算连续登录天数
        int daily_con = dailyLog.continuous_online_day;
        if (TimeTool.getDistanceDays(oldTime, nowTime) > 1) {
            daily_con = 1;
            careerLog.continuous_online_day = 1;
        } else {
            daily_con++;
            careerLog.continuous_online_day++;
        }
        // 生涯登录天数
        careerLog.online_day++;
        // 重置每日打点
        dailyLog = new RoleTraceDailyLog();
        initDaily();
        dailyLog.continuous_online_day = daily_con;
        long zeroTime = TimeTool.getZeroTimeStamp(nowTime);
        dailyLog.log_date = new Date(zeroTime);
        dailyLog.uid = dailyLog.role_id + "-" + zeroTime;
        // 记录一下在线时间
        recordOnlineTraceDaily();
    }

    /**
     * 初始化每日打点数据
     */
    private void initDaily() {
        long zeroTime = TimeTool.getZeroTimeStamp(System.currentTimeMillis());
        dailyLog.log_date = new Date(zeroTime);
        dailyLog.role_id = role.getUid();
        dailyLog.uid = dailyLog.role_id + "-" + zeroTime;
        dailyLog.open_id = role.getBase().openId;
        dailyLog.continuous_online_day = 1;
    }

    /**
     * 初始化生涯打点数据
     */
    private void initCareer() {
        careerLog.role_id = role.getUid();
        dailyLog.open_id = role.getBase().openId;
        careerLog.online_day = 1;
        careerLog.continuous_online_day = 1;
    }

    /**
     * 记录在线小时信息
     */
    public void recordOnlineTraceDaily() {
        Calendar c = Calendar.getInstance();
        int hour = c.get(Calendar.HOUR_OF_DAY);
        dailyLog.recordOnlineHour(hour);
    }

    /**
     * 记录在线时间
     */
    private void recordOnlineTime() {
        long nowTime = System.currentTimeMillis();
        long distance = nowTime - onlineStartTime;
        dailyLog.online_time += distance;
        careerLog.online_time += distance;
        onlineStartTime = nowTime;
    }

    /**
     * 记录进入公会时间
     */
    private void recordInClubTime(boolean force) {
        if (!force && role.getRes().guild.getGuild() == null) {
            return;
        }
        long nowTime = System.currentTimeMillis();
        long distance = nowTime - inClubStartTime;
        careerLog.in_club_time += distance;
        inClubStartTime = nowTime;
    }

    /**
     * 记录进入公会时间 非强制
     */
    private void recordInClubTime() {
        recordInClubTime(false);
    }

    /**
     * 存储日志
     */
    private void saveLog() {
        completeDaily();
        completeCareer();
        // TODO upsert接口目前不可用
        role.getGame().trace.log.saveDaily(dailyLog);
        role.getGame().trace.log.saveCareer(careerLog);
    }

    /**
     * 填充每日打点数据
     */
    private void completeDaily() {
        dailyLog.client_ip = role.getBase().login.ip;
        dailyLog.device_id = deviceId;
        dailyLog.client_version = clientVersion;
        dailyLog.platform = platform;
        dailyLog.register_time = new Date(role.getStatus().createTime);
        dailyLog.logout_time = new Date(role.getStatus().lastLogoutTime);
        dailyLog.username = role.getBase().name;
        dailyLog.current_level = role.getBase().level;
        dailyLog.server_id = role.getGame().config.srvId;
        dailyLog.power = role.getBase().power;
        dailyLog.diamond = role.getBag().numRes.countM1();
        dailyLog.gold = role.getBag().numRes.countM0();
        dailyLog.vip_level = role.getBase().vip;
        dailyLog.vip_exp = role.getBase().vipPoint;
        dailyLog.current_month_pass = role.getPay().tradeMall.monthCard.monthCardMap.values().stream()
                .anyMatch(statusPO -> statusPO.active);
        dailyLog.guide_id = guideId;
        dailyLog.main_task_id = role.getTask().mainline.curTaskId;
        dailyLog.adventure_id = role.getFarm().adventure.combatIdPassed;
        dailyLog.adventure_boss_id = role.getFarm().adventure.boss.bossPassedId;
        dailyLog.tower_id = role.getFarm().tower.passedFloor;
        dailyLog.forbidden_1_id = role.getFarm().forbidden.fbList.stream()
                .filter(po -> po.roomId == 1)
                .findAny()
                .map(po -> po.roundPass)
                .orElse(0);
        dailyLog.forbidden_2_id = role.getFarm().forbidden.fbList.stream()
                .filter(po -> po.roomId == 2)
                .findAny()
                .map(po -> po.roundPass)
                .orElse(0);
        dailyLog.forbidden_3_id = role.getFarm().forbidden.fbList.stream()
                .filter(po -> po.roomId == 3)
                .findAny()
                .map(po -> po.roundPass)
                .orElse(0);
        dailyLog.forbidden_4_id = role.getFarm().forbidden.fbList.stream()
                .filter(po -> po.roomId == 4)
                .findAny()
                .map(po -> po.roundPass)
                .orElse(0);
        dailyLog.forbidden_5_id = role.getFarm().forbidden.fbList.stream()
                .filter(po -> po.roomId == 5)
                .findAny()
                .map(po -> po.roundPass)
                .orElse(0);
        dailyLog.forbidden_6_id = role.getFarm().forbidden.fbList.stream()
                .filter(po -> po.roomId == 6)
                .findAny()
                .map(po -> po.roundPass)
                .orElse(0);
        dailyLog.daily_fb_1_id = role.getFarm().dailyFb.fbList.stream()
                .filter(fb -> fb.type == 1)
                .findAny()
                .map(fb -> fb.combatNumPass)
                .orElse(0);
        dailyLog.daily_fb_2_id = role.getFarm().dailyFb.fbList.stream()
                .filter(fb -> fb.type == 2)
                .findAny()
                .map(fb -> fb.combatNumPass)
                .orElse(0);
        dailyLog.daily_fb_3_id = role.getFarm().dailyFb.fbList.stream()
                .filter(fb -> fb.type == 3)
                .findAny()
                .map(fb -> fb.combatNumPass)
                .orElse(0);
        dailyLog.daily_fb_4_id = role.getFarm().dailyFb.fbList.stream()
                .filter(fb -> fb.type == 4)
                .findAny()
                .map(fb -> fb.combatNumPass)
                .orElse(0);
        dailyLog.daily_fb_5_id = role.getFarm().dailyFb.fbList.stream()
                .filter(fb -> fb.type == 5)
                .findAny()
                .map(fb -> fb.combatNumPass)
                .orElse(0);
        dailyLog.daily_fb_6_id = role.getFarm().dailyFb.fbList.stream()
                .filter(fb -> fb.type == 6)
                .findAny()
                .map(fb -> fb.combatNumPass)
                .orElse(0);
        dailyLog.daily_fb_7_id = role.getFarm().dailyFb.fbList.stream()
                .filter(fb -> fb.type == 7)
                .findAny()
                .map(fb -> fb.combatNumPass)
                .orElse(0);
        dailyLog.endless_id = role.getFarm().endless.combatCountMax;
        dailyLog.endless_count = role.getFarm().endless.combatNumPassed;
        dailyLog.island_id = role.getFarm().island.weekNo;
        dailyLog.friend_num = role.getFriend().list.size();
        dailyLog.in_club = role.getRes().guild.getGuild() != null;
        dailyLog.point_race_rank = role.getPvp().pointRace.getRank();
    }

    /**
     * 填充生涯打点数据
     */
    private void completeCareer() {
        careerLog.open_id = role.getBase().openId;
        careerLog.register_time = new Date(role.getStatus().createTime);
        careerLog.login_time = new Date(role.getStatus().loginTime);
        careerLog.logout_time = new Date(role.getStatus().lastLogoutTime);
        careerLog.server_id = role.getGame().config.srvId;
        careerLog.username = role.getBase().name;
        careerLog.current_level = role.getBase().level;
        careerLog.power = role.getBase().power;
        careerLog.diamond = role.getBag().numRes.countM1();
        careerLog.gold = role.getBag().numRes.countM0();
        careerLog.vip_level = role.getBase().vip;
        careerLog.vip_exp = role.getBase().vipPoint;
        careerLog.current_month_pass = role.getPay().tradeMall.monthCard.monthCardMap.values().stream()
                .anyMatch(statusPO -> statusPO.active);
        careerLog.guide_id = guideId;
        careerLog.main_task_id = role.getTask().mainline.curTaskId;
        careerLog.adventure_id = role.getFarm().adventure.combatIdPassed;
        careerLog.friend_num = role.getFriend().list.size();
        careerLog.in_club = role.getRes().guild.getGuild() != null;
        careerLog.point_race_rank = role.getPvp().pointRace.getRank();
    }

    /**
     * 充值触发
     *
     * @param pir      充值项配置
     * @param payCents 支付金额
     */
    public void onPay(PayItemRow pir, long payCents) {
        int payType = getPayType(pir);

        if (dailyLog.first_pay_time == null) {
            dailyLog.first_pay_time = new Date();
        }
        dailyLog.last_pay_time = new Date();
        dailyLog.total_pay_amount += payCents;
        dailyLog.total_pay_num++;
        if (dailyLog.first_recharge_num == 0) {
            dailyLog.first_recharge_num = payCents;
            dailyLog.first_recharge_type = payType;
        }

        if (careerLog.first_pay_time == null) {
            careerLog.first_pay_time = new Date();
            careerLog.first_buy_day = TimeTool.getDistanceDays(role.getStatus().createTime, System.currentTimeMillis()) + 1;
        }
        careerLog.last_pay_time = new Date();
        careerLog.total_pay_amount += payCents;
        careerLog.total_pay_num++;
        if (careerLog.first_recharge_num == 0) {
            careerLog.first_recharge_num = payCents;
            careerLog.first_recharge_type = payType;
        }
    }

    /**
     * 获取充值统计类型
     */
    private int getPayType(PayItemRow pir) {
        if (pir == null) {
            return TracePayType.OTHER;
        }
        switch (pir.funcId) {
            case GDFunc.TRADE_MALL_PAY_M1:
                return TracePayType.DIRECT;
            case GDFunc.TRADE_MALL_MONTH_CARD:
            case GDFunc.WEEK_CARD_SILVER:
            case GDFunc.WEEK_CARD_GOLD:
            case GDFunc.WEEK_CARD_RUNE_SILVER:
            case GDFunc.WEEK_CARD_RUNE_GOLD:
            case GDFunc.WEEK_CARD_SPICE_SILVER:
            case GDFunc.WEEK_CARD_SPICE_GOLD:
            case GDFunc.WEEK_CARD_GEM_SILVER:
            case GDFunc.WEEK_CARD_GEM_GOLD:
            case GDFunc.WEEK_CARD_ACT_ELITE_CALL:
            case GDFunc.WEEK_CARD_ACT_FURNITURE_CALL:
            case GDFunc.WEEK_CARD_ACT_HERO_CALL:
            case GDFunc.WEEK_CARD_ACT_M1:
            case GDFunc.WEEK_CARD_ACT_SPICE_CALL:
            case GDFunc.WEEK_CARD_ACT_WISH_CALL:
                return TracePayType.CARD;
            case GDFunc.WAR_ORDER:
            case GDFunc.TEMPLE_WAR_ORDER:
            case GDFunc.GOD_WAR_ORDER:
            case GDFunc.HERO_WAR_ORDER:
            case GDFunc.GOD_TREE_ORDER:
            case GDFunc.SKIN_WAR_ORDER:
            case GDFunc.SKIN_WAR_ORDER_2:
            case GDFunc.SKIN_WAR_ORDER_MKL:
            case GDFunc.GRADE_PVP_ORDER:
                return TracePayType.BP;
            case GDFunc.ACT_COND_SHOP_ROOKIE:
            case GDFunc.ACT_COND_SHOP_WEEK:
            case GDFunc.ACT_COND_SHOP_MONTH:
            case GDFunc.ACT_DAILY_SHOP_NEW_TWO:
                return TracePayType.SHOP;
            default:
                return TracePayType.OTHER;
        }
    }

    /**
     * 公会聊天
     */
    public void addGuildChat() {
        dailyLog.club_chat_count++;
        careerLog.club_chat_count++;
    }

    /**
     * 公共聊天
     */
    public void addPublicChat() {
        dailyLog.chat_count++;
        careerLog.chat_count++;
    }

    /**
     * 创建公会
     */
    public void createGuild() {
        careerLog.create_club_count++;
    }

    /**
     * 加入公会
     */
    public void joinGuild() {
        careerLog.join_club_count++;
        if (role.getStatus().isOnline()) {
            inClubStartTime = System.currentTimeMillis();
        }
    }

    /**
     * 离开公会
     */
    public void leaveGuild() {
        if (role.getStatus().isOnline()) {
            recordInClubTime(true);
        }
    }

    /**
     * 好友赠礼赠予
     *
     * @param times 赠予次数
     */
    public void giveFriendGift(int times) {
        dailyLog.friend_gift_give_count += times;
        careerLog.friend_gift_give_count += times;
    }

    /**
     * 好友赠礼领取
     *
     * @param times 领取次数
     */
    public void receiveFriendGift(int times) {
        dailyLog.friend_gift_get_count += times;
        careerLog.friend_gift_get_count += times;
    }

    /**
     * 积分赛挑战
     */
    public void challengePointRace() {
        dailyLog.point_race_count++;
        careerLog.point_race_count++;
    }

    /**
     * 日常副本挑战
     *
     * @param type 副本类型
     * @param times 挑战次数
     */
    public void challengeDailyFB(int type, int times) {
        dailyLog.addDailyFBCount(type, times);
    }

    /**
     * 迷失神庙挑战
     */
    public void challengeIsland() {
        dailyLog.island_count++;
    }
}
